/*
 * ResultMessage.java
 *
 * $Id: LocalizedResultMessage.java,v 1.1 2008-06-26 10:42:17 mario Exp $
 */
package org.ceteca.explica.core.util;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.StringTokenizer;

import org.xnap.commons.i18n.I18n;
import org.xnap.commons.i18n.I18nFactory;

/**
 * This class encapsulates the messages returned to the end user as the
 * result of any user operation in the system.
 * <br/>
 * Responsibilities:
 * <ul>
 * 	<li> Encapsulate and pass on the error messages to the end user. </li>
 * </ul>
 * <br/>
 * @author Mario García García <mario@imagos.es>
 * Copyright (c) 2007 Fundación Centro Tecnolóxico da Carne
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * <br/>
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * <br/>
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

public class LocalizedResultMessage implements Serializable {
private static final long serialVersionUID = 10000010;
	
	/**
	 * Internal result code to support result localization and classification.
	 * It may be either an OK code or any error code supported by the system.
	 */
	private int resCode;
	/**
	 * Result message string that is showed to the end user.
	 */
	private String resMessage;
	/**
	 * List of parameters used in the construction of the result message. 
	 * The number of parameters may vary according to the type of result
	 * message built.
	 */
	private ArrayList lParams;
	/**
	 * Error exception that generated the result message. Only applies when
	 * the result message is an error message.
	 */
	private Throwable exc;
	/**
	 * Name of the form field linked to the result message (for example for
	 * validation result messages). More than one field name can be linked
	 * by appending all the fields names using the "|" character as separator.
	 * Only applies when the result message is an error message.
	 */
	private String fieldName;
	
	private I18n i18n;

	/**
	 * Constructor for Simple ResultMessage class. Builds an appropriate
	 * result message for the result code. 
	 * @param resCode int, result message internal code.
	 */
	public LocalizedResultMessage(int resCode) {
		super();
		this.resCode = resCode;
		this.exc = null;
		this.lParams = null;
		this.i18n = I18nFactory.getI18n(this.getClass());
		this.fieldName = null;
		this.resMessage = null;
	}
	
	/**
	 * Constructor for Simple ResultMessage class. Builds an appropriate
	 * result message for the result code. 
	 * @param resCode int, result message internal code.
	 * @param i18n I18n, instance of Internationalization object.
	 */
	public LocalizedResultMessage(int resCode, I18n i18n) {
		super();
		this.resCode = resCode;
		this.exc = null;
		this.lParams = null;
		this.i18n = i18n;
		this.fieldName = null;
		this.resMessage = null;
	}
	
	/**
	 * Constructor for Parametrized ResultMessage class. Builds an appropriate
	 * result message for the result code, parametrizing the message with
	 * the right values. 
	 * @param resCode int, result message internal code.
	 * @param lParams ArrayList, list of the parameter values for the message. 
	 */
	public LocalizedResultMessage(int resCode, ArrayList lParams) {
		this.resCode = resCode;
		this.exc = null;
		this.lParams = lParams;
		this.i18n = I18nFactory.getI18n(this.getClass());
		this.fieldName = null;
		this.resMessage = null;
	}
	
	/**
	 * Constructor for Parametrized ResultMessage class. Builds an appropriate
	 * result message for the result code, parametrizing the message with
	 * the right values. 
	 * @param resCode int, result message internal code.
	 * @param lParams ArrayList, list of the parameter values for the message.
	 * @param i18n I18n, instance of Internationalization object. 
	 */
	public LocalizedResultMessage(int resCode, ArrayList lParams, I18n i18n) {
		this.resCode = resCode;
		this.exc = null;
		this.lParams = lParams;
		this.i18n = i18n;
		this.fieldName = null;
		this.resMessage = null;
	}
	
	/**
	 * Constructor for Parametrized Error ResultMessage class. Builds an appropriate
	 * result message for the result code, parametrizing the message with
	 * the right values and identifying the cause of the message. It also adds
	 * a form field linked to the result message. 
	 * @param resCode int, result message internal code.
	 * @param lParams ArrayList, list of the parameter values for the message.
	 * @param i18n I18n, instance of Internationalization object.
	 * @param fieldName String, form field's name linked to the result message. 
	 */
	public LocalizedResultMessage(int resCode, ArrayList lParams, I18n i18n, String fieldName) {
		this.resCode = resCode;
		this.exc = null;
		this.lParams = lParams;
		this.i18n = i18n;
		this.fieldName = fieldName;
		this.resMessage = null;
	}
	
	/**
	 * Constructor for Simple Error ResultMessage class. Builds an appropriate
	 * result message for the result code, identifying the cause of the message. 
	 * @param resCode int, result message internal code.
	 * @param cause Throwable, exception that raised the result message. Only
	 * applies with error messages.
	 */
	public LocalizedResultMessage(int resCode, Throwable cause) {
		this.resCode = resCode;
		this.exc = cause;
		this.lParams = null;
		this.i18n = I18nFactory.getI18n(this.getClass());
		this.fieldName = null;
		this.resMessage = null;
	}
	
	/**
	 * Constructor for Simple Error ResultMessage class. Builds an appropriate
	 * result message for the result code, identifying the cause of the message. 
	 * @param resCode int, result message internal code.
	 * @param cause Throwable, exception that raised the result message. Only
	 * applies with error messages.
	 * @param i18n I18n, instance of Internationalization object.
	 */
	public LocalizedResultMessage(int resCode, Throwable cause, I18n i18n) {
		this.resCode = resCode;
		this.exc = cause;
		this.lParams = null;
		this.i18n = i18n;
		this.fieldName = null;
		this.resMessage = null;
	}
	
	/**
	 * Constructor for Parametrized Error ResultMessage class. Builds an appropriate
	 * result message for the result code, parametrizing the message with
	 * the right values and identifying the cause of the message. 
	 * @param resCode int, result message internal code.
	 * @param cause Throwable, exception that raised the result message. Only
	 * applies with error messages.
	 * @param lParams ArrayList, list of the parameter values for the message. 
	 */
	public LocalizedResultMessage(int resCode, Throwable cause, ArrayList lParams) {
		this.resCode = resCode;
		this.exc = cause;
		this.lParams = lParams;
		this.i18n = I18nFactory.getI18n(this.getClass());
		this.fieldName = null;
		this.resMessage = null;
	}
	
	/**
	 * Constructor for Parametrized Error ResultMessage class. Builds an appropriate
	 * result message for the result code, parametrizing the message with
	 * the right values and identifying the cause of the message. It also adds
	 * a form field linked to the result message. 
	 * @param resCode int, result message internal code.
	 * @param cause Throwable, exception that raised the result message. Only
	 * applies with error messages.
	 * @param lParams ArrayList, list of the parameter values for the message.
	 * @param fieldName String, form field's name linked to the result message. 
	 */
	public LocalizedResultMessage(int resCode, Throwable cause, ArrayList lParams, String fieldName) {
		this.resCode = resCode;
		this.exc = cause;
		this.lParams = lParams;
		this.i18n = I18nFactory.getI18n(this.getClass());
		this.fieldName = fieldName;
		this.resMessage = null;
	}
	
	/**
	 * Constructor for Parametrized Error ResultMessage class. Builds an appropriate
	 * result message for the result code, parametrizing the message with
	 * the right values and identifying the cause of the message. 
	 * @param resCode int, result message internal code.
	 * @param cause Throwable, exception that raised the result message. Only
	 * applies with error messages.
	 * @param lParams ArrayList, list of the parameter values for the message.
	 * @param i18n I18n, instance of Internationalization object. 
	 */
	public LocalizedResultMessage(int resCode, Throwable cause, ArrayList lParams, I18n i18n) {
		this.resCode = resCode;
		this.exc = cause;
		this.lParams = lParams;
		this.i18n = i18n;
		this.fieldName = null;
		this.resMessage = null;
	}
	
	/**
	 * Constructor for Parametrized Error ResultMessage class. Builds an appropriate
	 * result message for the result code, parametrizing the message with
	 * the right values and identifying the cause of the message. It also adds
	 * a form field linked to the result message. 
	 * @param resCode int, result message internal code.
	 * @param cause Throwable, exception that raised the result message. Only
	 * applies with error messages.
	 * @param lParams ArrayList, list of the parameter values for the message.
	 * @param i18n I18n, instance of Internationalization object.
	 * @param fieldName String, form field's name linked to the result message. 
	 */
	public LocalizedResultMessage(int resCode, Throwable cause, ArrayList lParams, I18n i18n, String fieldName) {
		this.resCode = resCode;
		this.exc = cause;
		this.lParams = lParams;
		this.i18n = i18n;
		this.fieldName = fieldName;
		this.resMessage = null;
	}
	
	/**
	 * Gets the exception that raised the result message. It comes normally
	 * in error or warning messages.
	 * @return Throwable, exception linked to the result message.
	 */
	public Throwable getExc() {
		return exc;
	}
	/**
	 * Sets up the exception that raised the result message. It comes normally
	 * in error or warning messages.
	 * @param exc Throwable, exception linked to the result message.
	 */
	public void setExc(Throwable exc) {
		this.exc = exc;
	}

	/**
	 * Gets the list of parameters and their values, used in the
	 * construction of the result message.
	 * @return ArrayList, list of result message parameters.
	 */
	public ArrayList getLParams() {
		return lParams;
	}
	/**
	 * Sets up the list of parameters and their values, used in the
	 * construction of the result message.
	 * @param params ArrayList, list of result message parameters.
	 */
	public void setLParams(ArrayList params) {
		lParams = params;
	}

	/**
	 * Gets the result code for the result message. This code helps
	 * the coder to identify and locate the error source.
	 * @return int, result code.
	 */
	public int getResCode() {
		return resCode;
	}
	/**
	 * Sets up the result code for the result message. This code helps
	 * the coder to identify and locate the error source.
	 * @param resCode int, result code.
	 */
	public void setResCode(int resCode) {
		this.resCode = resCode;
	}

	/**
	 * Gets the message label that will be used for constructing
	 * the formatted error message. This label will be the base of the
	 * message, constructed also with the parameters specified and 
	 * using the internationalization mechanism to translate the message
	 * to the user's language it it's supported. 
	 * @return String, message label.
	 */
	public String getResMessage() {
		return resMessage;
	}
	/**
	 * Sets up the message label that will be used for constructing
	 * the formatted error message. This label will be the base of the
	 * message, constructed also with the parameters specified and 
	 * using the internationalization mechanism to translate the message
	 * to the user's language it it's supported. 
	 * @param resMessage String, message label.
	 */
	public void setResMessage(String resMessage) {
		this.resMessage = resMessage;
		
		// Localize the message to the user's locale
		this.resMessage = this.getLocalizedResultMessage();
	}
	
	/**
	 * Gets the name of the field that generated the error message.
	 * @return String, form field's name.
	 */
	public String getFieldName() {
		return fieldName;
	}

	/**
	 * Sets up the name of the field that generated the error message.
	 * @param fieldName String, form field's name.
	 */
	public void setFieldName(String fieldName) {
		this.fieldName = fieldName;
	}

	/**
	 * Constructs the formatted result message text.
	 * @return String, formatted result message text.
	 */
	public String getMessage() {
		return this.toString();
	}
	
	/**
	 * Format the result message to show it to the end user
	 * @return String, the formatted result message.
	 */
	public String toString() {
		StringBuffer msg = new StringBuffer();
		if (this.resMessage != null && this.resMessage.length() > 0) {
			msg.append(this.resMessage);
			
			if (this.exc != null) {
				msg.append("\n");
				ByteArrayOutputStream bos = new ByteArrayOutputStream();
				PrintWriter pw = new PrintWriter(bos);
				exc.printStackTrace(pw);
				pw.close();
				msg.append(bos.toString());
			}
			
		}
		
		return msg.toString();
	}
	
	/**
	 * Get the localized result message corresponding to the message code.
	 * @return String, localized result message corresponding to the message code.
	 */
	private String getLocalizedResultMessage() {
		String msg = "ERROR: " + this.resCode;
		if (this.i18n != null) {
			if (lParams != null && lParams.size() > 0)
				msg += "\n" + this.i18n.tr(this.resMessage, this.lParams.toArray());
			else
				msg += "\n" + this.i18n.tr(this.resMessage);
		}
		
		return msg;
	}

	/**
	 * Returns tag Id assigned to CVS source file.
	 */
	public static String getRevision() {
		return "$Id: LocalizedResultMessage.java,v 1.1 2008-06-26 10:42:17 mario Exp $";
	}
}
